Node.js 工作原理
运行时(Rutime System)与 node vm
Runtime system
运行时系统(Runtime system),又称之为 “运行环境”,指将半编译的代码运行的环境。在 node 核心概念中指的是 数据类型的确定 由编译时推迟到了运行时,因此就出现了运行时系统(Rutime System)来处理编译后的代码。
因此这个概念和流程就是 JavaScript 引擎负责解析和即时编译(JIT),结合 Rutime 因此可以实现了 Window 、DOM API,存在与浏览器的 Runtime 中。
所以 Node.js 中的 Runtime 也包含了不同的库,例如 Cluster、FileSystem API,这里面的 Runtime 都包含了内置的数据类型和常用的工具,因此 Chrome 和 Node.js 同样使用 V8 引擎但不会使用同一个 Runtime。
Cluster (集群)在 node v0.8 开始集成的内置模块,为解决单线程设计的瓶颈而生。
System Runtime :https://designfirst.io/systemruntime/,常见的运行时系统需要通过 C 或汇编而成,通过此项目可以简单构建
VM
VM 是 Node 核心模块之一,通过使用 V8 的 Virtual Machine Contexts 动态编译和执行代码,但代码的运行在上下文中是与当前隔离的,但他不是安全的,因此不要使用他来运行不受信任的代码。
不同与浏览器的沙箱环境, vm 提供了一系列的 API 用于在 V8 虚拟机中编译和运行代码,可以让 JavaScript 的代码被编译且立即运行或编译后保存运行:
1 | // 定义常量 |
vm.Script
是新增于 node.js v0.3.1 类,用于绑定任何全局对象,之后可以多次运行,也就是说我们将 sandbox
对象创建了环境的上下文,将对象绑定到环境中,因此最后输出 globalVar: 2, anotherGlobalVar: 1
这也就表明了 script.runInContext
在 contextifiedSandbox
上下文中运行,从而当 console.log
时,他的值已经改变了。
util.inspect
用于检查常量,除了script.runInContext
以外,在 node.js v6.3.0 中也完全支持了更为简单的方法vm.runlnContext
1 | const vm = require('vm') |
回调\同步\异步\阻塞\非阻塞
回调函数
在计算机的设计之初,基本上都是通过异步来进行的,在此之前我们需要知道异步的相关类别
Name | Info |
---|---|
同步 | 按照需求内的一步一步进行执行 |
异步 | 可以同时执行多种事情 |
堵塞 | 按照需求内一步一步进行,当一个程序没有执行,下面所排队等待的程序都处于排队状态 |
非堵塞 | 当一个程序没有执行完毕,后面所排队的程序都会进行插队 |
node.js 异步内的直接体现就在于回调,而回调就是,当你不知道用户何时会点击按钮,因此你为事件所定义了一个事件的处理程序,该事件会在处理时被触发调用即“回调”,我们以文件读取为例:
1 | var fs = require('fs'); |
以上的 js 脚本中那个,主要通过 fs.readFile
函数来异步读取文件,如果文件不存在则直接通过 err
输出错误信息,如没有发生错误则会忽略 err
对象进行输出,因此文件的内容就通过了回调函数输出:
1 | $ node vm.js |
假设 package.json
文件并不存在,那么在经过 s.readFile()
方法时,err
对象就会输出错误信息:
1 | $ node vm.js |
同步和异步的区别
同步可以说是一个进程在执行某一个请求的时候,另一个进程则需要等待,等上一个请求完后,这个进程才可以执行。而异步则是另一个进程无需等待,无论其他进程状态是否,直接进程执行。
1 | function __test() { |
首先我们需要注意的是,为了防止异步的出错,需要将 await
放到 try……catch
中,这就让 __test
与 test
两个函数同步起来,这样就会让输出的结果是__test
运行完了,test
还在等待的效果,正因这样,一个正常的运行结果才不会混乱。
堵塞
1 | var fs = require("fs") |
输出:
1 | hello |
在以上的code中,首先并不存在 hesllo.text 文件,处理回调错误的同时,在node中,任何回调函数中的地一个参数都为错误对象在Node官方文档中被标注为错误优先与回调
的说法。
非堵塞
1 | var fs = require("fs") |
输出:
1 | 程序执行完成 |
本文通过堵塞与非堵塞来进行演示,通常情况下堵塞代码是按照需求一步一步的执行,当一个步骤或没有完成时等待的程序处于排队状态
,而非堵塞则是不当一步骤没有执行完毕后面所排队的程序都会依次进行插队
即处理更加的效率
事件循环
Node.js 基本上所以的事件机制都使用类似与设计模式中的观察者模式实现,而观察者模式又是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个观察者的对象或其他对象。
观察者模式会在他本身的状态改变时发出通知,而这种呼叫各类观察者所提供的方式来实现,因此这种模式也被称之为事件处理系统。
在 node.js 中,所提供了 events
库,而他最主要的部分就是创建对象、事件处理、绑定事件以及最后的触发事件
1 | var events = require('events'); |
1 | 1.连接成功 |
上述 code 中 eventEmitter.emit()
用于触发事件,同时他也允许将任意一组参数传递给监听器函数,之后通过eventEmitter.on()
函数来注册监听器 connection ,最后通过 data_received
的事件绑定被监听器发现,从而输出整套流程。